今天要來談談 Generic。由於靜態語言對於宣告的類型有嚴格的規定,Generic 的出現則是讓這件事情變得更加彈性,可以將一套程式碼複用在不同類型的資料上。例如所謂 Generic class 或 Generic function 的參數就會除了一般的參數之外,也會有參數代表的是類型,也就是類型參數化。這樣子的好處是,就不用只是因為參數類型不同,就需要再撰寫一個很像的函式,例如把整數跟字串印出來的函數,可能邏輯上是完全一樣的,就不用特別寫像是 printInt 和 printStr。待會我們就會來看一些例子囉!
typing 的 Library 來提供像是 List、Tuple、Dict 等等 Type hints 供我們使用。例如下面的程式碼,我們從 typing 引入了 Dict, Tuple, List,而 Options、Host、Server 是 Type alias,可以讓我們自定義類型的別名以供後續使用,所以 connect 的參數 servers 就可以寫成 List[Server]。-> None 表示返回的是 None。from typing import Dict, Tuple, List
Options = Dict[str, str]
Host = Tuple[str, int]
Server = Tuple[Host, Options]
def connect(servers: List[Server]) -> None:
pass
T = TypeVar('T') 是定義了類型參數,而 Generic[T] 就是表示泛型,因此我們就可以在方法裡頭去標註類型參數了!T = TypeVar('T')
class LoggedVar(Generic[T]):
def set(self, new: T) -> None:
pass
def get(self) -> T:
pass
typing 有興趣的可以參考這裡囉!v interface{} 就是代表 v 可以是任何類型,而回傳也是任何類型。至於如何在程式裡頭去知道是什麼類型並做對應的事情呢?這裡用的是 Type switch,switch v.(type) 會去看傳入的 v 是不是 case 中的 Type,是的話就執行對應的程式。而 v.(int) 和 v.(float64) 是 Type assertion,例如 v.(int) 表示如果 v 是 int 就會得到真正這個 int 的值,假使不是 int 就會引發 panic。然而我們也可以這樣使用 i, ok := v.(int) 這樣就不會 panic,而是把是否是 int 這件事情存在 ok 之中囉!package main
import (
"reflect"
)
func Test(v interface{}) interface{} {
switch v.(type) {
case int:
return v.(int) + 10
case float64:
return v.(float64) + 22.3
}
return v
}